package org.dromara.file.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import io.minio.ObjectWriteResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.config.MinioConfig;
import org.dromara.common.core.enums.AuditEnum;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.FileOperateUtil;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.core.utils.file.MimeTypeUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.file.config.MinioUtil;
import org.dromara.file.domain.SysMediaFiles;
import org.dromara.file.domain.bo.SysMediaFilesBo;
import org.dromara.file.domain.vo.SysMediaFilesVo;
import org.dromara.file.mapper.SysMediaFilesMapper;
import org.dromara.file.service.ISysMediaFilesService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 文件管理Service业务层处理
 *
 * @author Gjb
 * @date 2025-06-09
 */
@RequiredArgsConstructor
@Service
@Slf4j
public class SysMediaFilesServiceImpl extends MPJBaseServiceImpl<SysMediaFilesMapper,SysMediaFiles> implements ISysMediaFilesService {

    private final SysMediaFilesMapper baseMapper;

    private final MinioConfig minioConfig;

    private final MinioUtil  minioUtil;
    /**
     * 查询文件管理
     */
    @Override
    public SysMediaFilesVo queryById(Long fileId){

        if(StringUtils.isNotNull(fileId)) {
            SysMediaFiles mediaFiles = baseMapper.selectById(fileId);
            if (mediaFiles == null) {
                return null;
            }
            SysMediaFilesVo vo = new SysMediaFilesVo();
            BeanUtils.copyProperties(mediaFiles, vo);
            vo.setUrl(mediaFiles.getServerUrl() + "/" + mediaFiles.getBucket() + mediaFiles.getFilePath());
            return vo;
        }
        return null;


    }

    /**
     * 查询文件管理列表
     */
    @Override
    public TableDataInfo<SysMediaFilesVo> queryPageList(SysMediaFilesBo bo, PageQuery pageQuery) {

        LambdaQueryWrapper<SysMediaFiles> lqw = buildQueryWrapper(bo);
        Page<SysMediaFilesVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询文件管理列表
     */
    @Override
    public List<SysMediaFilesVo> queryList(SysMediaFilesBo bo) {
        LambdaQueryWrapper<SysMediaFiles> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysMediaFiles> buildQueryWrapper(SysMediaFilesBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysMediaFiles> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getServerUrl()), SysMediaFiles::getServerUrl, bo.getServerUrl());
        lqw.eq(StringUtils.isNotBlank(bo.getBucket()), SysMediaFiles::getBucket, bo.getBucket());
        lqw.eq(StringUtils.isNotBlank(bo.getFilePath()), SysMediaFiles::getFilePath, bo.getFilePath());
        lqw.eq(bo.getFileType() != null, SysMediaFiles::getFileType, bo.getFileType());
        lqw.eq(bo.getFileSize() != null, SysMediaFiles::getFileSize, bo.getFileSize());
        lqw.like(StringUtils.isNotBlank(bo.getFileName()), SysMediaFiles::getFileName, bo.getFileName());
        lqw.eq(StringUtils.isNotBlank(bo.getFileMd5()), SysMediaFiles::getFileMd5, bo.getFileMd5());
        lqw.eq(StringUtils.isNotBlank(bo.getTarget()), SysMediaFiles::getTarget, bo.getTarget());
        lqw.eq(StringUtils.isNotBlank(bo.getExtension()), SysMediaFiles::getExtension, bo.getExtension());
        lqw.eq(bo.getAuditStatus() != null, SysMediaFiles::getAuditStatus, bo.getAuditStatus());
        lqw.eq(StringUtils.isNotBlank(bo.getAuditMind()), SysMediaFiles::getAuditMind, bo.getAuditMind());
        lqw.eq(bo.getUserId() != null, SysMediaFiles::getUserId, bo.getUserId());
        lqw.like(StringUtils.isNotBlank(bo.getUserName()), SysMediaFiles::getUserName, bo.getUserName());
        lqw.eq(bo.getSchoolId() != null, SysMediaFiles::getSchoolId, bo.getSchoolId());
        lqw.like(StringUtils.isNotBlank(bo.getSchoolName()), SysMediaFiles::getSchoolName, bo.getSchoolName());
        return lqw;
    }

    /**
     * 新增文件管理
     */
    @Override
    public Boolean insertByBo(SysMediaFilesBo bo) {
        SysMediaFiles add = MapstructUtils.convert(bo, SysMediaFiles.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setFileId(add.getFileId());
        }
        return flag;
    }

    /**
     * 修改文件管理
     */
    @Override
    public Boolean updateByBo(SysMediaFilesBo bo) {
        SysMediaFiles update = MapstructUtils.convert(bo, SysMediaFiles.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysMediaFiles entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除文件管理
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {

        for (Long id : ids.stream().toList()) {
            SysMediaFiles mediaFiles = baseMapper.selectById(id);
            if (StringUtils.isNotNull(mediaFiles)) {
                //从Minio中删除 并且从数据库中删除
                try {
                    minioUtil.removeFile(mediaFiles.getBucket(), mediaFiles.getFilePath());

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }

            }

        }

        return  this.baseMapper.deleteBatchIds(ids)>0;

    }

    @Override
    public void downloadFile(HttpServletRequest request, HttpServletResponse response, String bucketName, String objectName, String contentType) {
        try {
            InputStream inputStream = minioUtil.getObject(bucketName, objectName);
            FileOperateUtil.download(request,response,"",contentType,inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public SysMediaFilesVo uploadFile(MultipartFile file, String objectName) {
        try {
            //文件名
            String filename = file.getOriginalFilename();
            //扩展名
            String extension = FileUtils.getFileExtension(filename);

            //mineType
            String mimeType = MimeTypeUtils.getMimeType(extension);

            //文件上传目录
            String defaultFolderPath = FileUtils.getDefaultFolderPath();

            File tempFile = File.createTempFile("minio", ".temp");
            file.transferTo(tempFile);
            String localFilePath = tempFile.getAbsolutePath();
            //文件MD5
            String fileMd5 = FileUtils.getFileMd5(new File(localFilePath));
            if (StringUtils.isEmpty(objectName)) {
                objectName = defaultFolderPath + fileMd5 + extension;
            }
            //上传到Minio
            ObjectWriteResponse objectWriteResponse = minioUtil.uploadFile(minioConfig.getBucketName(), objectName, localFilePath, mimeType);

            //封装MediaFiles
            SysMediaFilesBo mediaFilesBo = new SysMediaFilesBo();
            //获取文件信息
            mediaFilesBo.setAuditStatus(AuditEnum.AUDIT.getCode());
            mediaFilesBo.setFileMd5(fileMd5);
            mediaFilesBo.setBucket(minioConfig.getBucketName());
            mediaFilesBo.setFileName(filename);
            mediaFilesBo.setFileSize(file.getSize());
            mediaFilesBo.setExtension(extension);
//            mediaFiles.setId(fileMd5);
            mediaFilesBo.setFilePath("/" + objectName);
            mediaFilesBo.setFileType(1L);

            SysMediaFiles mediaFiles = addMediaFilesToDB(mediaFilesBo);
            SysMediaFilesVo vo = new SysMediaFilesVo();
            BeanUtils.copyProperties(mediaFiles,vo);
            return vo;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public SysMediaFiles addMediaFilesToDB(SysMediaFilesBo bo) {

        String tenantId = TenantHelper.getTenantId();
        if(tenantId == null||tenantId.equals("")){
            throw new ServiceException("未找到匹配的架构！");
        }

        SysMediaFiles mediaFiles = this.selectMediaFilesByFileMd5TenantId(bo.getFileMd5(), tenantId);

        if (mediaFiles == null) {
            mediaFiles = new SysMediaFiles();
            BeanUtils.copyProperties(bo, mediaFiles);
            mediaFiles.setServerUrl(minioConfig.getUrl());
            mediaFiles.setUserId(LoginHelper.getUserId());
            mediaFiles.setUserName(LoginHelper.getUsername());
//            mediaFiles.setSchoolId(schoolId);
//            mediaFiles.setSchoolName(SecurityUtils.getLoginUser().getSysUser().getSchoolName());
            int insert = baseMapper.insert(mediaFiles);

            if (insert <= 0) {
                log.info("向数据库保存文件失败,bucket:{},objectName:{}", bo.getBucket(), bo.getFileName());
                return null;
            }
            //记录待处理的任务
           // mediaProcessService.addWaitingTask(mediaFiles);
            return mediaFiles;
        }

        log.info("资源已存在无需重复上传");
        return mediaFiles;

    }

    @Override
    public SysMediaFiles selectMediaFilesByFileMd5TenantId(String fileMd5, String tenantId) {
        LambdaQueryWrapper<SysMediaFiles> lqw = new LambdaQueryWrapper<SysMediaFiles>();
        lqw.eq(StringUtils.isNotNull(fileMd5),SysMediaFiles::getFileMd5,fileMd5);
        lqw.eq(StringUtils.isNotNull(tenantId),SysMediaFiles::getTenantId,tenantId);
        return this.baseMapper.selectOne(lqw);
    }
}
